package com.zdb.java.misc;

import org.junit.Test;
import sun.misc.Unsafe;

public class UnsafeTest {

    /**
     * 测试unsafe 使用堆外内存
     * //分配size字节大小的内存，返回起始地址偏移量
     * public native long allocateMemory(long size);
     * //重新给address起始地址的内存分配长度为size字节大小的内存，返回新的内存起始地址偏移量
     * public native long reallocateMemory(long address, long size);
     * //释放起始地址为address的内存
     * public native void freeMemory(long address);
     */
    @Test
    public void testUnsafeMemory() {
        Unsafe unsafe = GetUsafeInstance.getInstance();
        /**
         * 在堆外分配一个byte
         */
        long allocatedAddress = unsafe.allocateMemory(1L);
        unsafe.putByte(allocatedAddress, (byte) 100);
        byte shortValue = unsafe.getByte(allocatedAddress);
        System.out.println(new StringBuilder().append("Address:")
                .append(allocatedAddress).append(" Value:")
                .append(shortValue));

        /**
         * 重新分配一个long
         */
        allocatedAddress = unsafe.reallocateMemory(allocatedAddress, 8L);
        unsafe.putLong(allocatedAddress, 1024L);
        long longValue = unsafe.getLong(allocatedAddress);
        System.out.println(new StringBuilder().append("Address:")
                .append(allocatedAddress).append(" Value:")
                .append(longValue));

        /**
         * Free掉,这个数据可能脏掉
         */
        unsafe.freeMemory(allocatedAddress);
        longValue = unsafe.getLong(allocatedAddress);
        System.out.println(new StringBuilder().append("Address:")
                .append(allocatedAddress).append(" Value:")
                .append(longValue));
    }

    /**
     * 测试unsafe申请的内存的释放
     * -XX:+PrintGCDetails
     */
    @Test
    public void testUnsafeMemoryOutMemory() {
        Unsafe unsafe = GetUsafeInstance.getInstance();
//        while (true) {
            Long address = unsafe.allocateMemory(1L);
            Long src = Integer.MAX_VALUE + 1024L;
            unsafe.putLong(address,  src);
        System.out.println("src:" + src);

            long res = unsafe.getLong(address);
        System.out.println("res:" + res);


        long address2 = unsafe.allocateMemory(1);
        unsafe.putLong(address2, 2048L);
        long res2 = unsafe.getLong(address2);
        System.out.println("res2:" + res2);


        res = unsafe.getLong(address);
        System.out.println("res:" + res);


        while(true) {
            long size = 1024 * 1024;
            long addr = unsafe.allocateMemory(size * 1024 * 1024);
            System.out.println("申请了" + size + "M内存：" + addr);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        }
    }

    /**
     * 测试unsafe申请的内存的释放
     * -XX:+PrintGCDetails
     */
    @Test
    public void testUnsafeMemoryFree() {
        while (true) {
            ObjectInHeap heap = new ObjectInHeap();
            System.out.println("memory address=" + heap.getAddress());
        }
    }
}

class ObjectInHeap {
    private long address;

    private Unsafe unsafe = GetUsafeInstance.getInstance();

    byte[] bytes;

    public ObjectInHeap() {
        address = unsafe.allocateMemory(2 * 1024 * 1024);
        // 为了触发jvm GC
//        bytes = new byte[2*1024*1024];
    }

    public long getAddress() {
        return address;
    }

    @Override protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("-- 释放堆外内存：" + address);
//        unsafe.freeMemory(address);
    }
}
